package ccm.communicate.tcp;

import ccm.common.Configurable;
import ccm.common.ReceiveDataEvent;
import ccm.common.StatusChangeEvent;
import ccm.communicate.common.Communicate;
import ccm.communicate.common.NotStartException;
import ccm.communicate.common.SendFailedException;

import javax.swing.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;

public class TcpServer extends Communicate implements Configurable
{
    /**
     * 保存端口号
     */
    protected       int          port     =3333;
    final protected Receiver[]   receivers=new Receiver[1];
    /**
     * 保存链接
     */
    protected       ServerSocket serverSocket;

    public TcpServer()
    {
        super();
    }

    public int getPort()
    {
        return port;
    }

    public void setPort(int port)
    {
        boolean is=isOpen();
        if(is)
            stop();
        this.port=port;
        if(is)
            start();

    }

    /**
     * 获取配置用的面板
     *
     * @return 配置用的面板
     */
    public JPanel getConfigJPanel()
    {
        return new TcpServerConfigJPanel(this);
    }

    /**
     * 启动
     */
    public void start()
    {
        try
        {
            serverSocket=new ServerSocket(port);
            for(int i=0;i<receivers.length;++i)
                (receivers[i]=new Receiver()).start();
            statusChange(StatusChangeEvent.START_STOP);
        }catch(IOException e)
        {
            e.printStackTrace();
            serverSocket=null;
        }
    }

    /**
     * 停止
     */
    public void stop()
    {
        try
        {
            if(serverSocket!=null)
                serverSocket.close();
        }catch(IOException ex)
        {
            ex.printStackTrace();
        }
        serverSocket=null;
        statusChange(StatusChangeEvent.START_STOP);
    }

    /**
     * 检查是否开启
     *
     * @return true表示开启
     * false表示关闭
     */
    public boolean isOpen()
    {
        return (serverSocket!=null&&!serverSocket.isClosed());
    }

    /**
     * 发送数据
     *
     * @param data    数据
     * @param channel 通道
     * @throws NotStartException   未启动时抛出此异常
     * @throws SendFailedException 发送失败时抛出此异常
     * @implNote 通道未使用
     */
    public void send(byte[] data,int channel) throws NotStartException, SendFailedException
    {
        if(!isOpen())
            throw new NotStartException();
        try
        {
            for(Receiver receiver: receivers)
                receiver.send(data);
        }catch(IOException e)
        {
            e.printStackTrace();
            throw new SendFailedException();
        }
    }

    /**
     * 用于保存参数
     */
    public void writeExternal(ObjectOutput out) throws IOException
    {

    }

    /**
     * 用于加载参数
     */
    public void readExternal(ObjectInput in) throws IOException
    {

    }

    private class Receiver extends Thread
    {
        private Socket client;

        public void run()
        {
            while(serverSocket!=null)
            {
                try
                {
                    client=serverSocket.accept();
                    client.setSoTimeout(10000);
                    System.out.println("与客户端"+client.getInetAddress()+"连接成功！");
                    InputStream inputStream=client.getInputStream();
                    while(!client.isClosed())
                    {
                        try
                        {
                            byte[] buffer=new byte[1024];
                            int len;
                            if((len=inputStream.read(buffer))!=-1)
                            {
                                byte[] buf=new byte[len];
                                System.arraycopy(buffer,0,buf,0,len);
                                ReceiveDataEvent e=new ReceiveDataEvent(this,buf);
                                for(int i=0;i<receiveDataListener.length;++i)
                                    callReceiveDataListener(i,e);
                            }
                        }catch(SocketTimeoutException e)
                        {
                            e.printStackTrace();
                            System.out.println("数据读取超时。");
                            if(client!=null)
                                client.close();
                            break;
                        }
                    }
                }catch(Exception e)
                {
                    e.printStackTrace();
                }
                System.out.println("与客户端连接断开！");
                client=null;
            }
        }

        public void send(byte[] data) throws IOException
        {
            if(client!=null)
                client.getOutputStream().write(data);
        }
    }
}
